/*
 * I write in my free time, for personal using
 * when i fell proud of it, i will give it to public
 * now,have nothing more to say
 */
package com.quangtin3.utils;

/**
 * From java thread programming
 * @author paul hyde
 */
public class BooleanLock extends Object {

    private boolean value;

    /**
     * BooleanLock construction, state set to false
     */
    public BooleanLock() {
        this(false);
    }

    /**
     * BooleanLook construction
     * @param value
     */
    public BooleanLock(boolean value) {
        this.value = value;
    }

    /**
     * set state to "newValue"
     * @param newValue
     */
    public synchronized void setValue(boolean newValue) {
        if (newValue != value) {
            value = newValue;
            this.notifyAll();
        }
    }

    /**
     * wait until state is true and set it to true
     * will return if timeout or throw InterruptedException if been interrupted
     * @param msTimeOut
     * @return
     * @throws java.lang.InterruptedException
     */
    public synchronized boolean waitToSetTrue(long msTimeOut) throws InterruptedException {
        boolean success = waitUntilFalse(msTimeOut);
        if (success) {
            setValue(true);
        }
        return success;
    }

    /**
     * wait until state is true and set it to false
     * will return if timeout or throw InterruptedException if been interrupted
     * @param msTimeOut
     * @return
     * @throws java.lang.InterruptedException
     */
    public synchronized boolean waitToSetFalse(long msTimeOut) throws InterruptedException {
        boolean success = waitUntilTrue(msTimeOut);
        if (success) {
            setValue(false);
        }
        return success;
    }

    /**
     * wait until state is True or timeout
     * will throw InterrupedException if been interrupted while waiting
     * @param msTimeOut
     * @return
     * @throws java.lang.InterruptedException
     */
    public synchronized boolean waitUntilTrue(long msTimeOut) throws InterruptedException {
        return waitUntilStateIs(true, msTimeOut);
    }

    /**
     * wait until state is False or timeout
     * will throw InterrupedException if been interrupted while waiting
     * @param msTimeOut
     * @return
     * @throws java.lang.InterruptedException
     */
    public synchronized boolean waitUntilFalse(long msTimeOut) throws InterruptedException {
        return waitUntilStateIs(false, msTimeOut);
    }

    public synchronized boolean isTrue() {
        return value;
    }

    public synchronized boolean isFalse() {
        return !value;
    }

    /**
     * wail until state of this object is "state" or time out.
     * if it been interrupted when waitting, willl throw InterrupedException
     * @param state
     * @param msTimeOut
     * @return
     * @throws java.lang.InterruptedException
     */
    public synchronized boolean waitUntilStateIs(boolean state, long msTimeOut)
            throws InterruptedException {
        if (msTimeOut == 0L) {
            while (value != state) {
                this.wait();
            }
            return true;
        }

        long endTime = System.currentTimeMillis() + msTimeOut;
        long remainTime = msTimeOut;

        while (value != state && remainTime > 0L) {
            this.wait(remainTime);
            remainTime = endTime - System.currentTimeMillis();
        }

        return (value == state);
    }
}
